package com.ayf.payment.game.api.task.order;

import com.ayf.payment.game.api.config.SystemInitialization;
import com.ayf.payment.game.api.dto.OrderAndMerchantDTO;
import com.ayf.payment.game.api.entity.Order;
import com.ayf.payment.game.api.service.OrderService;
import com.ayf.payment.game.api.service.payment.PaymentHandleFactory;
import com.ayf.payment.game.api.type.OrderStatus;
import com.ayf.payment.game.api.utils.DateUtils;
import com.ayf.payment.game.api.utils.SnowFlakeUtils;
import com.github.pagehelper.PageHelper;
import com.swwx.charm.commons.lang.utils.LogPortal;
import com.swwx.charm.zookeeper.exception.GetLockFailedException;
import com.swwx.charm.zookeeper.exception.ReleaseLockFailedException;
import com.swwx.charm.zookeeper.lock.DistributedLock;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Component;

import java.util.Date;
import java.util.List;
import java.util.concurrent.CountDownLatch;

/**
 * @Author: zh-liang
 * @Date : 2019-12-19
 */
@Component
public abstract class ProcessResultQueryTask {

    // 订单状态
    private final static OrderStatus orderStatus = OrderStatus.PROCESSING;
    @Autowired
    private OrderService orderService;

    @Autowired
    private SystemInitialization systemInitialization;

    @Autowired
    PaymentHandleFactory paymentHandleFactory;

    /**
     * 执行各个支付渠道的订单状态查询
     *
     * @throws GetLockFailedException
     */
    protected void run(DistributedLock distributedLock) {
        boolean lock = false;
        String traceId = SnowFlakeUtils.getTraceId();
        String lockName = this.getClass().getSimpleName().concat(System.getenv("XY_GAME_PAY_LOCK_FLAG"));
        try {
            if (lock = distributedLock.getLock(lockName)) {
                LogPortal.info("{} >>> get lock and run {} ", traceId, lockName);
                long time= DateUtils.getMillisAfterMillis2(new Date(),0);
                int count = 0;
                Order temp = new Order();
                temp.setOrderStatus(orderStatus);
                count = orderService.selectCountAlterTime(temp,time);
                LogPortal.info("{} >>> [{}]处理总条数[{}]", traceId, lockName, count);
                if (count <= 0) {
                    return;
                }
                final int pageSize = 100;
                int totalPage = count % pageSize == 0 ? (count / pageSize) : (count / pageSize) + 1;
                for (int i = 0; i < totalPage; i++) {
                    PageHelper.startPage(i, pageSize);
                    final List<OrderAndMerchantDTO> list = orderService.selectProcessingOrder(orderStatus,time);
                    LogPortal.info("{} >>> {} 开始处理处理中交易第[{}]页[{}]条记录", traceId, lockName, (i + 1), list.size());
                    //初始化信号
                    final CountDownLatch countDownLatch = new CountDownLatch(list.size());
                    for (final OrderAndMerchantDTO dto : list) {
                        submit(new Runnable() {
                            @Override
                            public void run() {
                                try {
                                    LogPortal.error("{} 商户ID[{}] 商户订单号[{}] 订单查询 Strat", traceId,dto.getMerchantId(),dto.getMerchantOrderNo());
                                    orderService.updateOrderStatus(dto.getMerchantOrderNo(),time);
                                } catch (Exception e) {
                                    LogPortal.error("{} 商户ID[{}] 商户订单号[{}] 订单查询发生了{}异常，错误描述:{}", traceId,dto.getMerchantId(),dto.getMerchantOrderNo(),e.getClass().getName(),e.getMessage());
                                }finally {
                                    //线程执行完成之后标记信号表示完成
                                    countDownLatch.countDown();
                                }
                            }
                        });
                    }
                    //等待线程池任务执行完毕
                    countDownLatch.await();
                }
            } else {
                LogPortal.info("{} >>> {} do not get lock ", traceId, lockName);
            }
        } catch (GetLockFailedException e) {
            LogPortal.error("{} >>> [DISTRIBUTED_LOCK_ACQUIRE_FAILED_ZK] 分布式锁获取失败,锁名称为:{}", traceId, lockName);
            LogPortal.error("{} >>> {} 获取lock失败", e, traceId, lockName);
        } catch (Exception e) {
            LogPortal.error("{} >>> {} 任务执行出错 ", e, traceId, lockName);
        } finally {
            if (lock) {
                LogPortal.info(traceId + " >>> " + lockName + " finished.");
                try {
                    distributedLock.releaseLock(lockName);
                } catch (ReleaseLockFailedException e) {
                    LogPortal.error("{} >>> [DISTRIBUTED_LOCK_RELEASE_FAILED_ZK] 分布式锁释放失败,锁名称为:{}", traceId, lockName);
                    LogPortal.error("{} >>> {} 释放失败", e, traceId, lockName);
                }
            }
        }
    }

    public abstract void submit(Runnable task);
}
